<script>
import { cloneDeep } from 'lodash'
import { h, resolveComponent } from 'vue'
import AppWidget from '../widgets/AppWidget'
import AppGroupWidget from '../widgets/AppGroupWidget'
import SearchBarWidget from '../widgets/SearchBarWidget'
import WeatherWidget from '../widgets/WeatherWidget'
import TaskPanelWidget from '../widgets/TaskPanelWidget.vue'
import RssWidget from '../widgets/RssWidget.vue'
import GridLayout from 'src/components/grid/GridLayout'
import GridItem from 'src/components/grid/GridItem'
import { diffArrayById } from '../../../utils/widget'
import IframeWidget from '../widgets/IframeWidget'
import RichTextWidget from '../widgets/RichTextWidget'
import CustomWidget from '../widgets/CustomWidget'

export default {
  name: 'WidgetGrid',
  components: {
    AppWidget,
    AppGroupWidget,
    SearchBarWidget,
    WeatherWidget,
    TaskPanelWidget,
    RssWidget,
    IframeWidget,
    RichTextWidget,
    CustomWidget,
    GridLayout,
    GridItem
  },
  props: {
    widgets: {
      type: Array,
      default: () => []
    }
  },
  data () {
    return {
      renderWidgets: cloneDeep(this.widgets),
      // 调试相关
      log: true,
      // 拖拽交互
      dropActive: false,
      dropEnter: false,
      layout: this.widgets.map(e => {
        return {
          x: e.x,
          y: e.y,
          w: e.w,
          h: e.h,
          id: e.id
        }
      })
    }
  },
  provide () {
    return {
      widgetGrid: this
    }
  },
  computed: {
    float () {
      return this.$store.state.widget.options.float
    }
  },
  render () {
    const mask = h('div')
    return h('div', {}, [
      h(GridLayout, {
        ref: 'grid',
        class: [
          'widget-grid',
          { 'widget-grid--drop-active': this.dropActive },
          { 'widget-grid--drop-enter': this.dropEnter }
        ],
        layout: this.renderWidgets,
        colNum: 10,
        rowHeight: 116,
        maxRows: 24,
        minRows: 10,
        isDraggable: true,
        isResizable: true,
        isMirrored: false,
        verticalCompact: !this.float,
        margin: [0, 0],
        useCssTransforms: true,
        preventCollision: false,
        freezeTime: 100,
        itemHover: true,
        // [?] .sync 暂时没啥用 - 组件直接偷偷改传入对象状态了
        'onUpdate:layout': event => {
          this.layout = event
        },
        onLayoutUpdated: layout => {
          this.onLayout(layout)
        },
        onDragendCover: event => {
          const updatingItem = event.updatingItem
          const coverLayoutItem = event.coverLayoutItem
          const movingWidget = this.widgets.find(e => e.id === updatingItem.id)
          const coveredWidget = this.widgets.find(e => e.id === coverLayoutItem.id)
          this.$store.dispatch('widget/mergeAppWidget', {
            movingWidgetId: movingWidget.id,
            coveredWidgetId: coveredWidget.id
          })
        },
        onDropActive: () => {
          this.dropActive = true
        },
        onDragEnter: () => {
          this.dropEnter = true
        },
        onDragLeave: () => {
          this.dropEnter = false
        },
        onDrop: event => {
          const appId = event.relatedTarget.id
          // 滞后调用 - 因为应用组内应用会触发 dragend - updated-layout
          this.$nextTick(() => {
            this.$store.dispatch('widget/moveOutAppFromWidget', { appId })
          })
        },
        onDropDeactivate: () => {
          this.dropActive = false
          this.dropEnter = false
        }
      }, {
        default: () => this.renderWidgets.map(widget => {
          if (!widget.type) {
            return null
          }
          return h(resolveComponent(widget.type), {
            key: widget.id,
            data: widget
          })
        })
      }),
      mask
    ])
  },
  watch: {
    widgets: {
      handler (newWidgets, oldWidgets) {
        console.log('=> WidgetGrid Layout', 'full change:', newWidgets === oldWidgets)
        if (newWidgets !== oldWidgets) {
          // 重置所有 Widget
          this.renderWidgets = cloneDeep(this.widgets)
        } else {
          // 部分更新 Widget
          const {
            appends,
            retains
          } = diffArrayById(newWidgets, oldWidgets)
          this.renderWidgets = [
            ...retains.map(newWidget => {
              const oldRenderWidget = this.renderWidgets.find(j => newWidget.id === j.id)
              if (JSON.stringify(newWidget) === JSON.stringify(oldRenderWidget)) {
                return oldRenderWidget
              }
              return cloneDeep(newWidget)
            }),
            ...appends.map(e => {
              const widget = cloneDeep(e)
              widget.id = e.id
              return widget
            })
          ]
        }
      },
      deep: true
    }
  },
  methods: {
    onLayout (layout) {
      console.log('<= WidgetGrid Layout')
      this.$store.dispatch('storeSave', layout)
    }
  }
}

</script>

<style lang="scss">

.widget-grid {
  transition: all 0.5s;

  > .widget-grid-item {
    z-index: 10;
    cursor: default;
    display: inline-block;
    position: relative;
    min-height: 116px;
    min-width: 116px;
    touch-action: none;

    > .widget-grid-item-content {
      overflow: visible;
      position: relative;
      inset: 5px;
      width: calc(100% - 10px);
      height: calc(100% - 10px);
      transition: box-shadow .3s;

      &:hover {
        box-shadow: 1px 1px 6px white !important;
      }
    }

    &.sub {
      //background-color: #21BA45;
    }

    &-removing {
      opacity: 0.5;
    }

    // [?] Special rule
    &.AppGroupWidget {
      z-index: 20;
    }
  }

  &--drop-active {
    .widget-grid-item {
      filter: blur(3px);
      // [?] Special rule
      &.AppGroupWidget {
        filter: initial;
      }
    }
  }

  &--drop-enter {
    background-color: rgba(245, 237, 237, 0.58);
  }

}

.drop-active-mask {
  content: "";
  width: 100%;
  height: 100%;
  position: absolute;
  left: 0;
  top: 0;
  background: rgba(0, 0, 0, 0.8);
  z-index: 15;
  // border: 2px solid black;
}

</style>
